package com.bsfcs.rag.service;

import com.alibaba.fastjson.JSON;
import com.bsfcs.rag.entity.Project;
import com.bsfcs.rag.entity.Task;
import com.bsfcs.rag.entity.WorkHour;
import com.bsfcs.rag.repository.ProjectRepository;
import com.bsfcs.rag.repository.TaskRepository;
import com.bsfcs.rag.repository.WorkHourRepository;
import lombok.Getter;
import lombok.Setter;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import reactor.core.publisher.Flux;

@Service
public class ProjectTaskWorkHourService {
    private final ChatClient chatClient;

    @Autowired
    private ProjectRepository projectRepository;
    @Autowired
    private TaskRepository taskRepository;
    @Autowired
    private WorkHourRepository workHourRepository;


    ProjectTaskWorkHourService(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder.build();
    }
    
    /**
     * 根据项目ID获取项目及其所有任务和工时信息
     * @param projectId 项目ID
     * @return 项目信息，包含任务和工时
     */
    public ProjectWithTasksAndWorkHours getProjectWithTasksAndWorkHours(String projectId) {
        Project project = projectRepository.findById(projectId).orElse( null);
        if (project == null) {
            return null;
        }
        
        List<Task> tasks = taskRepository.findByParentId(projectId);
        List<String> taskIds = tasks.stream().map(Task::getId).collect(Collectors.toList());
        List<WorkHour> workHours = workHourRepository.findByIds(taskIds);
        
        // 将工时信息挂到对应的任务下
        List<TaskWithWorkHours> tasksWithWorkHours = tasks.stream().map(task -> {
            List<WorkHour> taskWorkHours = workHours.stream()
                    .filter(workHour -> workHour.getParentId().equals(task.getId()))
                    .collect(Collectors.toList());
            return new TaskWithWorkHours(task, taskWorkHours);
        }).collect(Collectors.toList());
        
        return new ProjectWithTasksAndWorkHours(project, tasksWithWorkHours);
    }

    public AggregatedProjectData getAggregatedProjectData(String projectId) {
        ProjectWithTasksAndWorkHours projectData = getProjectWithTasksAndWorkHours(projectId);
        if (projectData == null) {
            return null;
        }

        return aggregateProjectData(projectData);
    }

    @Getter
    @Setter
    public static class AggregatedProjectData {
        private String projectId;
        private String projectCode;
        private String projectName;
        private List<AggregatedTaskData> tasks;


        public String toModelString() {
            StringBuilder sb = new StringBuilder();
            sb.append("项目:\n");
            sb.append("  编号: ").append(projectCode).append("\n");
            sb.append("  名称: ").append(projectName).append("\n");
            if (tasks != null && !tasks.isEmpty()) {
                sb.append("  任务:\n");
                for (AggregatedTaskData task : tasks) {
                    sb.append(task.toModelString(2)); // 缩进层级
                }
            }
            return sb.toString();
        }
    }

    @Getter
    @Setter
    public static class AggregatedTaskData {
        private String taskId;
        private String taskTitle;
        private String taskState;
        private String taskPriority;
        private String charger; // 负责人
        private BigDecimal estimatedTime; // 预估工时
        private BigDecimal registrationTime; // 登记工时
        private BigDecimal remainingTime; // 剩余工时
        private String startTime; // 开始时间
        private String endTime; // 结束时间
        private List<AggregatedWorkHourData> workHours;

        public String toModelString(int indentLevel) {
            String indent = "  ".repeat(indentLevel);
            String subIndent = "  ".repeat(indentLevel + 1);
            StringBuilder sb = new StringBuilder();
            sb.append(indent).append("- 任务:\n");
            sb.append(subIndent).append("名称: ").append(taskTitle).append("\n");
            sb.append(subIndent).append("状态: ").append(taskState).append("\n");
            sb.append(subIndent).append("优先级: ").append(taskPriority).append("\n");
            sb.append(subIndent).append("负责人: ").append(charger).append("\n");
            sb.append(subIndent).append("预估工时: ").append(estimatedTime).append("\n");
            sb.append(subIndent).append("登记工时: ").append(registrationTime).append("\n");
            sb.append(subIndent).append("剩余工时: ").append(remainingTime).append("\n");
            sb.append(subIndent).append("开始时间: ").append(startTime).append("\n");
            sb.append(subIndent).append("结束时间: ").append(endTime).append("\n");

            if (workHours != null && !workHours.isEmpty()) {
                sb.append(subIndent).append("工时:\n");
                for (AggregatedWorkHourData wh : workHours) {
                    sb.append(wh.toModelString(indentLevel + 2));
                }
            }
            return sb.toString();
        }
    }

    @Getter
    @Setter
    public static class AggregatedWorkHourData {
        private String registrant; // 登记人
        private String jobCategory; // 工作类别
        private String jobDate; // 工作日期
        private BigDecimal jobDuration; // 工作时长
        private String description; // 描述

        public String toModelString(int indentLevel) {
            String indent = "  ".repeat(indentLevel);
            StringBuilder sb = new StringBuilder();
            sb.append(indent).append("- 工时:\n");
            sb.append(indent).append("  登记人: ").append(registrant).append("\n");
            sb.append(indent).append("  工作类别: ").append(jobCategory).append("\n");
            sb.append(indent).append("  工作日期: ").append(jobDate).append("\n");
            sb.append(indent).append("  工作时长 (小时): ").append(jobDuration).append("\n");
            sb.append(indent).append("  描述: ").append(description).append("\n");
            return sb.toString();
        }
    }

    /**
     * 聚合项目数据，减少数据量
     * @param projectData 原始项目数据
     * @return 聚合后的项目数据
     */
    private AggregatedProjectData aggregateProjectData(ProjectWithTasksAndWorkHours projectData) {
        String json = JSON.toJSONString(projectData);
        Project project = projectData.getProject();
        List<TaskWithWorkHours> tasks = projectData.getTasks();

        // 聚合项目信息
        AggregatedProjectData aggregatedData = new AggregatedProjectData();
        aggregatedData.setProjectId(project.getId());
        aggregatedData.setProjectCode(project.getProject_code());
        aggregatedData.setProjectName(project.getProject_name());

        // 聚合任务信息
        List<AggregatedTaskData> aggregatedTasks = tasks.stream().map(taskWithHours -> {
            Task task = taskWithHours.getTask();
            List<WorkHour> workHours = taskWithHours.getWorkHours();

            AggregatedTaskData aggregatedTask = new AggregatedTaskData();
            aggregatedTask.setTaskId(task.getId());
            aggregatedTask.setTaskTitle(task.getTitle());
            aggregatedTask.setTaskState(task.getStates());
            aggregatedTask.setTaskPriority(task.getPriority());
            aggregatedTask.setCharger(task.getCharger());
            aggregatedTask.setEstimatedTime(task.getEstimated_time());
            aggregatedTask.setRegistrationTime(task.getRegistration_time());
            aggregatedTask.setRemainingTime(task.getRemaining_time());
            aggregatedTask.setStartTime(task.getStart_time_str());
            aggregatedTask.setEndTime(task.getEnd_time_str());

            // 聚合工时信息
            List<AggregatedWorkHourData> aggregatedWorkHours = workHours.stream().map(workHour -> {
                AggregatedWorkHourData aggregatedWorkHour = new AggregatedWorkHourData();
                aggregatedWorkHour.setRegistrant(workHour.getRegistrant());
                aggregatedWorkHour.setJobCategory(workHour.getJob_category());
                aggregatedWorkHour.setJobDate(workHour.getJob_date_str());
                aggregatedWorkHour.setJobDuration(workHour.getJob_duration());
                aggregatedWorkHour.setDescription(workHour.getDescribe());
                return aggregatedWorkHour;
            }).collect(Collectors.toList());

            aggregatedTask.setWorkHours(aggregatedWorkHours);
            return aggregatedTask;
        }).collect(Collectors.toList());

        aggregatedData.setTasks(aggregatedTasks);
        return aggregatedData;
    }
    
    /**
     * 获取所有项目及其关联的任务和工时信息
     * @return 项目列表，包含任务和工时
     */
    public List<ProjectWithTasksAndWorkHours> getAllProjectsWithTasksAndWorkHours() {
        List<Project> projects = projectRepository.findAll();
        List<String> projectIds = projects.stream().map(Project::getId).collect(Collectors.toList());
        
        List<Task> tasks = taskRepository.findByParentIds(projectIds);
        List<String> taskIds = tasks.stream().map(Task::getId).collect(Collectors.toList());
        List<WorkHour> workHours = workHourRepository.findByIds(taskIds);
        
        return projects.stream().map(project -> {
            List<Task> projectTasks = tasks.stream()
                    .filter(task -> task.getParentId().equals(project.getId()))
                    .collect(Collectors.toList());
            
            // 将工时信息挂到对应的任务下
            List<TaskWithWorkHours> tasksWithWorkHours = projectTasks.stream().map(task -> {
                List<WorkHour> taskWorkHours = workHours.stream()
                        .filter(workHour -> workHour.getParentId().equals(task.getId()))
                        .collect(Collectors.toList());
                return new TaskWithWorkHours(task, taskWorkHours);
            }).collect(Collectors.toList());
            
            return new ProjectWithTasksAndWorkHours(project, tasksWithWorkHours);
        }).collect(Collectors.toList());
    }
    
    // 新增：根据项目ID获取JSON格式数据
    public Flux<String> getProjectWithTasksAndWorkHoursAsJson(String projectId) throws JsonProcessingException {
        AggregatedProjectData result = getAggregatedProjectData(projectId);
        if (result == null) {
            return null;
        }
        String modelString = result.toModelString();

        return this.chatClient.prompt()
                .system(systemSpec -> systemSpec
                        .text("""
                                  你是一名高级项目经理和分析专家，擅长从项目管理的原始数据中提炼出深刻的、可执行的商业洞察。你的核心职责是分析提供的项目数据，并专注于项目绩效、资源效率和风险预测。
                                    你的任务是从用户提供的原始数据中提取结论，不得添加任何未经证实的信息或假设。如果数据不足以支持某个结论，请回答“数据不足，无法判断”。禁止编造、猜测、 extrapolation（外推）、插值或虚构任何数值、事件、来源。所有输出必须能追溯到输入数据中的原文或计算结果。
                             
                                      请严格遵守以下规则：
                                      1.  **角色定位**：以专业、严谨、客观的口吻进行汇报，避免主观臆测。
                                      2.  **数据驱动**：所有结论必须有数据支撑，引用具体数值（如项目ID、任务名称、人员名称、工时数、日期等）。
                                      3.  **结构化输出**：你的回答必须采用清晰的Html格式，包含标题、段落、列表和表格（如需要），确保可读性。
                                      4.  **关注重点**：优先分析项目健康度、工时偏差、任务延期和资源分配问题。
                                      5.  **提供建议**：在分析末尾，必须基于发现的问题提供具体、可操作的建议，而不是泛泛而谈。
                                      6.  **输出要求**：
                                          6.1. 输出为标准的div块，所有 CSS 必须以内联 style 属性写在元素上，body样式不要使用body关键词，使用mybody。
                                          6.2. 页面整体风格简洁现代，采用浅色背景（#f9f9f9），深色标题（#2c3e50）。
                                          6.3. 报告标题居中显示，字号 26px，字体 Arial，字重 bold。
                                          6.4. 每个分析模块（如项目健康度、任务效率、人力资源等）请使用卡片式布局：
                                             - 白色背景
                                             - 圆角（8px）
                                             - 阴影（0 2px 6px rgba(0,0,0,0.1)）
                                             - 上下间距 20px
                                             - 内边距 15px
                                          6.5. 二级标题（h2）左侧带一条 4px 宽的蓝色边线（#3498db）。
                                          6.6. 表格使用隔行变色（浅灰色 #f2f2f2）并在鼠标 hover 时高亮。
                                          6.7. 输出时请只给出最终 HTML，不要包含推理过程。
                               
                                      请首先确认理解上述指令。
                                """))
                .user(userSpec -> userSpec
                        .text("""
                                  请根据以下JSON数据，生成一份关于该项目的全面绩效分析报告。
                                  不得添加任何未经证实的信息或假设。如果数据不足以支持某个结论，请回答“数据不足，无法判断”。禁止编造、猜测、 extrapolation（外推）、插值或虚构任何数值、事件、来源。所有输出必须能追溯到输入数据中的原文或计算结果
                                  **分析核心要求：**
                                  1.  **项目总体健康度**：计算并对比总预估工时和总实际工时，分析进度偏差。
                                  2.  **任务效率分析**：找出效率最高和最低的3个任务（对比实际工时与预估工时），并分析可能的原因。
                                  3.  **人力资源分析**：
                                      -   计算每位成员的总投入工时。
                                      -   识别工作量最饱和和最不饱和的成员。
                                      -   检查是否有成员在“游离工时”上投入过多时间，这可能意味着任务分配或管理流程存在问题。
                                  4.  **风险预警**：指出目前延期风险最高的任务，并预测其对项目总进度的影响。
                                  5.  **改进建议**：根据以上分析，提供3条最迫切的、可操作的改进建议。
                                
                                  **项目数据如下：**
                                  ```json
                                  {projectInfo}
                                """)
                        .param("projectInfo", modelString))

                .stream()
                .content();
    }
    
    // 新增：获取所有项目及其关联信息的JSON格式数据
    public String getAllProjectsWithTasksAndWorkHoursAsJson() throws JsonProcessingException {
        List<ProjectWithTasksAndWorkHours> results = getAllProjectsWithTasksAndWorkHours();
        ObjectMapper objectMapper = new ObjectMapper();
        return objectMapper.writeValueAsString(results);
    }
    
    // 内部类用于封装项目及其关联信息
    @Getter
    public static class ProjectWithTasksAndWorkHours {
        // Getters and setters
        private Project project;
        private List<TaskWithWorkHours> tasks;
        
        public ProjectWithTasksAndWorkHours(Project project, List<TaskWithWorkHours> tasks) {
            this.project = project;
            this.tasks = tasks;
        }

        public void setProject(Project project) {
            this.project = project;
        }

        public void setTasks(List<TaskWithWorkHours> tasks) {
            this.tasks = tasks;
        }
    }
    
    // 新增内部类用于封装任务及其工时信息
    public static class TaskWithWorkHours {
        private Task task;
        private List<WorkHour> workHours;
        
        public TaskWithWorkHours(Task task, List<WorkHour> workHours) {
            this.task = task;
            this.workHours = workHours;
        }
        
        // Getters and setters
        public Task getTask() {
            return task;
        }
        
        public void setTask(Task task) {
            this.task = task;
        }
        
        public List<WorkHour> getWorkHours() {
            return workHours;
        }
        
        public void setWorkHours(List<WorkHour> workHours) {
            this.workHours = workHours;
        }
    }
}